

//**************
//Game Framework
//**************

//Game Implementation (level 2, game specific)
//      Entity definitions
//      Gameplay definitions
//-------------------
//      |
//      |
//     \/
//Engine Implementation (level 1, platform specific)
//      Concrete components
//      Concrete component factory
//---------------------
//      |
//      |
//     \/
//Core Engine (level 0, completely general)
//      Component interfaces
//      Component factory interface
//      Game class

#ifndef GAMEENGINE_H
#define GAMEENGINE_H

#include "Maths.h"
#include "String.h"

//(level 0 code)

//Forward declaration of the core game object
class Game;

//Code Game component interfaces
//------------------------------
//INFO: These component interfaces are all friends of the Game class so that only it can call their private
//      update routines. Their public interfaces are the only things accessible to the rest of the game.
//NOTE: These are not strictly interfaces as they contain a pointer to their owner game.
class IRenderer
{
     friend class Game;
protected:
    
    Game* m_pOwner;
    
    IRenderer(Game* pOwner) : m_pOwner(pOwner)      {}
    virtual ~IRenderer()        {}
    
    virtual bool init(String sTitle, int iWidth, int iHeight, int iBitsPerPixel, bool bFullscreen) = 0;
    virtual void resize(int iWidth, int iHeight) = 0;
    //Called once per frame (at start)
    virtual bool update() = 0;
    //Called once per frame (at end)
    virtual void renderScene() = 0;
    
    //Returns whether the renderer device is active and thus whether the game loop should pause
    virtual bool isActive() = 0;
    //Returns whether the renderer has received a quit message and thus the game loop should end
    virtual bool isQuit() = 0;
    
public:
    
    //TODO: We may want to add some basic drawing methods here, e.g., rectangles, circles, text etc.
    ////virtual void setColor() = 0;
    ////virtual void drawTri(double fCoords[3]) = 0;
    
    //TODO: Should create a GfxModel object that contains all of the data necessary for
    //      rendering a graphical model. This method can then be used to render the object
    //      according to the implementation.
    //virtual void drawModel( GfxModel* pModel ) = 0;

};

class IInput
{
	
	//KeyDown('A') --> read by IInput (level 1) --> passed into bindings --> event
	//Key binding code is level 1
	//Using the key binding code is level 2
	
	//Example key bindings
	//--------------------
	//Action	Key1	Key2
	//--------------------
	//Left		A	Left
	//Right		D	Right
	//Jump		Space	-
	//--------------------
	//Action	Key1	Key2
	//--------------------
	//Charge	Mouse1	LCONTROL
	//Pause		P	-
	//Main Menu	Escape	-
	
	struct KeyBinding {
		CClientEvent* pDownEvent;
		CClientEvent* pUpEvent;
	};
	
	KeyBinding m_Bindings[256];
	
	void bindEventToKeyDown(CClientEvent* event, primaryKey, secondaryKey)
	{
		m_Bindings[primaryKey].pDownEvent = event;
		m_Bindings[secondaryKey] = event;
	}
	
	//Also have continuous input, e.g., mouse position
	
	
    friend class Game;
protected:
    
    Game* m_pOwner;
    
    IInput(Game* pOwner) : m_pOwner(pOwner)      {}
    virtual ~IInput()        {}
    
    //Gathers all of the input data
	virtual void update() = 0;
    
public:
    
    typedef unsigned char Key;
    
	//Mouse movement
	virtual Vector 		getMousePos() = 0;
	virtual Vector		getMouseMoveVector() = 0;
	virtual Scalar		getMouseMoveAngle() = 0;
	virtual Scalar 		getMouseMoveDistance() = 0;
	virtual bool 		isMouseMoved() = 0;
    
	//Key presses (includes mouse clicks)
	virtual bool getKeyState(Key k) = 0;
	virtual bool getKeyDown(Key k) = 0;
	virtual bool getKeyUp(Key k) = 0;
    
};

class IAudio
{
    friend class Game;
protected:
    
    Game* m_pOwner;
    
    IAudio(Game* pOwner) : m_pOwner(pOwner)      {}
    virtual ~IAudio()        {}
    
    virtual void update() = 0;
    
public:
    
    //virtual void getSound(String sName) = 0;
    //virtual void playSound(String sName) = 0;
    
};

class IWorld
{
    friend class Game;
protected:
    
    Game* m_pOwner;
    
    IWorld(Game* pOwner) : m_pOwner(pOwner)      {}
    virtual ~IWorld()        {}
    
    //Perform all entity updating and 
    virtual void update() = 0;
    
    //Draw all entities
    virtual void draw() = 0;
    
public:
    
    //virtual Entity* addEntity(Entity* e) = 0;
    //virtual void removeEntity(String sName) = 0;
    //virtual Entity* getEntity(String sName) = 0;
    
};
//------------------------------

//THOUGHT: For now, don't worry about making a completely data-driven engine (far too much work: scripting, 
//          parsing, string manipulation etc.). Instead, just try to make a framework where code that will
//          change often is well-separated from code that won't. e.g., Gameplay code should be in very
//          distinct classes that only deal with that, not intermingled with engine code.

//An interface for creating the game components
class IGameComponentFactory
{
    friend class Game;
protected:
    
    //Override these to return new game component objects
    virtual IRenderer*  createRenderer(Game* pOwner) = 0;
    virtual IInput*     createInput(Game* pOwner) = 0;
    virtual IAudio*     createAudio(Game* pOwner) = 0;
    virtual IWorld*     createWorld(Game* pOwner) = 0;
    
};

//The core game object
class Game
{
    
    //Note: Could make these components in a map, but no point, as they are so fundamental
    //      Basically, two ways to do it. Can have hard-coded interface objects that will cover any conceivable
    //      requirements, or, can have dynamic component system with onStartOfFrame, onEndOfFrame, etc.
    //      The problem with dynamic component system is type casting. Will have to keep casting retrieved objects
    //      into their known types in order to access specific functionality. Also, could have components only
    //      for gameplay, and not for fundamental game engine components.
    IRenderer*  m_pRenderer;
    IInput*     m_pInput;
    IAudio*     m_pAudio;
    IWorld*     m_pWorld;
    
    //TODO: Consider other components: Event system, Network.
    
    bool m_bRunning;
    
public:
    
    Game(IGameComponentFactory* componentFactory)
    {
        //Create the game components
        m_pRenderer = componentFactory->createRenderer(this);
        m_pInput = componentFactory->createInput(this);
        m_pAudio = componentFactory->createAudio(this);
        m_pWorld = componentFactory->createWorld(this);
    }
    
    void init(String sTitle, int iWidth, int iHeight, int iBitsPerPixel, bool bFullscreen)
    {
        
        
        
        m_pRenderer->init(sTitle, iWidth, iHeight, iBitsPerPixel, bFullscreen);
        
    }
    
    void start()
    {
        
        while (m_bRunning) {
            
            //Update the renderer
    		if (m_pRenderer->update())
                continue;
    		
    		//Make sure the renderer is currently active
    		if (!m_pRenderer->isActive())
                continue;
    
    		//Check if the Engine has recieved a quit message
    		if (m_pRenderer->isQuit())
                m_bRunning = false;
            
            m_pInput->update();
            m_pWorld->update();
            m_pWorld->draw();
            m_pAudio->update();
            m_pRenderer->renderScene();
            
        }
        
    }
    
};

#endif //GAMEENGINE_H
